<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/11/13
 * Time: 15:43
 */

namespace common\business\task;

use common\business\CommonHelper;
use common\business\company\CompanyTaskHandler;
use common\business\department\DepartmentKd2QywxTaskHandler;
use common\business\department\DepartmentTaskHandler;
use common\business\empdept\EmployeeDepartmentTaskHandler;
use common\business\employee\EmployeeExcelTaskHandler;
use common\business\employee\EmployeeTaskHandler;
use common\business\empphoto\EmployeePhotoTaskHandler;
use common\business\emppos\EmployeePositionTaskHandler;
use common\business\mdm\MdmDeptTaskHandler;
use common\business\mdm\MdmEmployeeTaskHandler;
use common\business\mdm\MdmOrgTaskHandler;
use common\business\mdm\MdmPositionTaskHandler;
use common\business\mdmtask\MdmTaskTaskHandler;
use common\business\org\OrgTreeTaskHandler;
use common\business\position\PositionTaskHandler;
use common\business\qywx\QywxDepartmentCascadeDeleteTaskHandler;
use common\business\qywx\QywxDepartmentTaskHandler;
use common\business\qywx\QywxUserTaskHandler;
use common\consts\CommonResources;
use common\helpers\StringUtil;
use Yii;
use common\consts\Consts;
use common\helpers\DateHelper;
use common\models\Task;
use yii\base\Exception;
use yii\base\UserException;
use yii\helpers\Json;

class TaskHelper
{
    /**
     * 处理Task
     *
     * @param Task $task
     * @return TaskResponseData
     */
    public static function processTask($task){
        $service = new TaskService();
        return $service->processTask($task);
    }

    /**
     * 根据Task Type 获取异步任务Handler
     * @param $task Task
     * @return null|TaskHandlerInterface
     */
    public static function getTaskHandler($task)
    {
//        if (array_key_exists(trim($task->type), Yii::$app->params['taskHandlers'])) {
//            $taskHandlerName = Yii::$app->params['taskHandlers'][trim($task->type)];
//
//            return Yii::createObject($taskHandlerName);
//        } else {
//            return null;
//        }
        switch ($task->type){
            case Consts::TASK_TYPE_EMPLOYEE:
                return new EmployeeTaskHandler();
            case Consts::TASK_TYPE_COMPANY:
                return new CompanyTaskHandler();
            case Consts::TASK_TYPE_DEPARTMENT:
                return null;
            case Consts::TASK_TYPE_EXCEL_TO_EMPLOYEE:
                return new EmployeeExcelTaskHandler();
            case Consts::TASK_TYPE_DEPARTMENT_FROM_QYWX:
                return new QywxDepartmentTaskHandler();
            case Consts::TASK_TYPE_KD_TO_QYWX:
                return new DepartmentKd2QywxTaskHandler();
            case Consts::TASK_TYPE_CASCADE_DELETE_QYWX_DEPARTMENT:
                return new QywxDepartmentCascadeDeleteTaskHandler();
            case Consts::TASK_TYPE_EMPLOYEE_DEPARTMENT:
                return new EmployeeDepartmentTaskHandler();
            case Consts::TASK_TYPE_EMPLOYEE_TO_QYWX:
                return new QywxUserTaskHandler();
            case Consts::TASK_TYPE_POSITION:
                return new PositionTaskHandler();
            case Consts::TASK_TYPE_EMPLOYEE_POSITION:
                return new EmployeePositionTaskHandler();
            case Consts::TASK_TYPE_DEPARTMENT_FROM_HR:
                return new DepartmentTaskHandler();
            case Consts::TASK_TYPE_DEPARTMENT_TO_QYWX:
                return new QywxDepartmentTaskHandler();
            case Consts::TASK_TYPE_ORG_TO_TREE:
                return new OrgTreeTaskHandler();
            case Consts::TASK_TYPE_EMPLOYEE_PHOTO:
                return new EmployeePhotoTaskHandler();
            case Consts::TASK_TYPE_MDM_ORG:
                return new MdmOrgTaskHandler();
            case Consts::TASK_TYPE_MDM_TASK:
                return new MdmTaskTaskHandler();
            case Consts::TASK_TYPE_MDM_DEPT:
                return new MdmDeptTaskHandler();
            case Consts::TASK_TYPE_MDM_POSITION:
                return new MdmPositionTaskHandler();
            case Consts::TASK_TYPE_MDM_EMPLOYEE:
                return new MdmEmployeeTaskHandler();
            default:
                return null;
        }
    }


    /**
     * @param int $priority
     * @return array|null|\yii\db\ActiveRecord
     */
    public static function getTopOneNeedProcessAsyncTask($priority = 1){
        return Task::find()
            ->where([
                'priority'           => $priority,
                'status'             => [Consts::TASK_STATUS_OPEN, Consts::TASK_STATUS_ERROR],
                'is_synchronization' => Consts::NO,
            ])
//            ->andWhere(['>', 'next_run_date', DateHelper::getCurrentDateTime(-120)])
            ->andWhere(['<=', 'next_run_date', DateHelper::getCurrentDateTime()])
            ->orderBy(['id' => SORT_ASC,])
            ->limit(1)
            ->select(['id'])
            ->asArray()
            ->one();
    }

    /**
     * 获取前100条需要异步处理的任务.并且这些任务需要最近半个小时内处理完成
     *
     * @return array|\yii\db\ActiveRecord[]
     */
    public static function getTop100NeedProcessAsyncTask($sliceCount, $totalSliceCount, $priority)
    {
        return Task::find()
            ->where([
                'priority'           => $priority,
//                'status'             => [Consts::TASK_STATUS_OPEN, Consts::TASK_STATUS_ERROR],
            //错误的不再跑
                'status'             => [Consts::TASK_STATUS_OPEN],
                'is_synchronization' => Consts::NO,
            ])
            ->andWhere(['>', 'next_run_date', DateHelper::getCurrentDateTime(-120)])
            ->andWhere(['<=', 'next_run_date', DateHelper::getCurrentDateTime()])
            ->andWhere(sprintf("mod(id,%s)=%s", $totalSliceCount, $sliceCount))
            ->orderBy(['id' => SORT_ASC,])
            ->limit(100)
            ->select(['id'])
            ->asArray()
            ->all();
    }

    /**
     * 获取前100条需要异步处理的任务.并且这些任务需要最近半个小时前的处理完成
     *
     * @return array|\yii\db\ActiveRecord[]
     */
    public static function getTop100NeedProcessOneHourBeforeAsyncTask()
    {
        return Task::find()
            ->andWhere(['<=', 'next_run_date', DateHelper::getCurrentDateTime(-120)])
            ->andWhere(['=', 'is_synchronization', '0'])
            ->andWhere([
                'or',
                ['status' => Consts::TASK_STATUS_OPEN],
                ['status' => Consts::TASK_STATUS_ERROR],
            ])
            ->orderBy(['id' => SORT_ASC,])
            ->limit(100)
            ->select(['id'])
            ->asArray()
            ->all();
    }

    /**
     * @param $task Task
     * @param $totalCount integer
     * @param $finishCount integer
     * @param $message string
     */
    public static function writeBackAlways($task, $totalCount, $finishCount, $message){
        try {
            $task->total_number = $totalCount;
            $task->finished_number = $finishCount;
            if ($totalCount == $finishCount || $totalCount == 0){
                $newRate = Yii::t('app', 'In Process...');
            }
            else {
                $newRate = strval(round(($finishCount / $totalCount * 100), 2));
            }
            $task->finish_rate = $newRate;
            if(!StringUtil::isNullOrWhiteSpace($message)){
                $task->response_data = $message;
            }
            if (!$task->save()){
                throw new UserException(CommonResources::ACTION_FAIL_MSG('Write Back', 'Task', Json::encode($task->getErrors())));
            }
        } catch (Exception $e) {
            echo CommonHelper::getExceptionMsg($e);
        }
    }

    /**
     * @param $task Task
     * @param $totalCount integer
     * @param $finishCount integer
     * @param $message string
     */
    public static function finishTask($task, $totalCount, $finishCount, $message){
        try {
            $task->total_number = $totalCount;
            $task->finished_number = $finishCount;
            $task->finish_rate = '100';
            if(!StringUtil::isNullOrWhiteSpace($message)){
                $task->response_data = $message;
            }
            if (!$task->save()){
                throw new UserException(CommonResources::ACTION_FAIL_MSG('Write Back', 'Task', Json::encode($task->getErrors())));
            }
        } catch (Exception $e) {
            echo CommonHelper::getExceptionMsg($e);
        }
    }

    /**
     * @param $task Task
     * @param $totalCount integer
     * @param $finishCount integer
     * @param $message string
     */
    public static function writeBackFinishPercentage($task, $totalCount, $finishCount, $message){
        try {
            $task->total_number = $totalCount;
            $task->finished_number = $finishCount;
            $newRate = strval(round(($finishCount / $totalCount * 100), 2));
//                每几个百分点更新一次
            if (($task->finished_number == $totalCount) || ($newRate - $task->finish_rate) >= Consts::RATE_RANGE) {
                $task->finish_rate = $newRate;
                if(!StringUtil::isNullOrWhiteSpace($message)){
                    $task->response_data = $message;
                }
                if (!$task->save()){
                    throw new UserException(CommonResources::ACTION_FAIL_MSG('Write Back', 'Task', Json::encode($task->getErrors())));
                }
//                sleep(1);
            }
        } catch (Exception $e) {
            echo CommonHelper::getExceptionMsg($e);
        }
    }
}